import axios, { formToJSON } from 'axios';
import redis from './redis.js';
import mysqlHelper from './mysqlHelper.js';
import logger from './logger.js';
import redisHelper from './redisHelper.js';

const dbIndex = 13;
async function post(url, data, timeout = 10000) {
    // 默认超时时间为10秒
    const startTime = Date.now(); // 记录开始时间
    try {
        let res = await axios.post(url, data, { timeout });
        const endTime = Date.now(); // 记录结束时间
        const duration = endTime - startTime; // 计算耗时
        logger.info('post请求成功', `url:${url} 耗时 ${duration}ms 入参：${JSON.stringify(data)} 出参:${JSON.stringify(res.data)}`); // 记录耗时
        return res.data;
    } catch (e) {
        const endTime = Date.now(); // 记录结束时间
        const duration = endTime - startTime; // 计算耗时
        logger.error('post请求失败', `url:${url} 入参：${JSON.stringify(data)} 错误信息:${e.message} 耗时:${duration}ms`);
        return null;
    }
}

/**
 * 发送请求失败则缓存到重发机制里面
 * @param {string} url 请求url
 * @param {any} data 请求数据
 * @param {import("./common/table.js").ProjectInfo.table} projectInfo 项目信息
 * @param {number} [retryCount=0] 重试次数
 * @param {number} [retryId] 重试记录ID
 * @returns {Promise<any>}
 */
async function retryRequest(url, data, projectInfo, retryCount = 0, retryId) {
    try {
        const response = await axios.post(url, data, { timeout: 5000 });
        logger.info('请求成功', `url:${url} 入参：${JSON.stringify(data)} 项目信息:${JSON.stringify(projectInfo)} 响应信息:${JSON.stringify(response.data)}`);
        if (retryId) {
            await mysqlHelper.excute('DELETE FROM retry_todo WHERE id = ?', [retryId]);
        }
        return response;
    } catch (error) {
        logger.warn('请求失败', `url:${url} 入参：${JSON.stringify(data)} 项目信息:${JSON.stringify(projectInfo)} 错误信息:${error.message}`);
        await addToRetryTodo(url, data, projectInfo, retryCount, retryId);
    }
}

/**
 * 添加到重试机制
 * @param {string} url 请求url
 * @param {any} data 请求数据
 * @param {import("./common/table.js").ProjectInfo.table} projectInfo 项目信息
 * @param {number} retryCount 重试次数
 * @param {number} [retryId] 重试记录ID
 * @returns {Promise<void>}
 */
async function addToRetryTodo(url, data, projectInfo, retryCount, retryId) {
    const expireTime = calculateExpireTime(retryCount);

    if (expireTime === null) {
        // 如果超过最大重试次数，则记录错误并退出
        logger.error('重试机制', `url:${url} 入参：${JSON.stringify(data)} 项目信息:${JSON.stringify(projectInfo)} 失败次数超过20次不再重试`);
        return;
    }

    try {
        let id;
        if (retryCount === 0) {
            // 插入新记录
            const result = await mysqlHelper.query('INSERT INTO retry_todo (url, data, park_no, retry_count) VALUES (?, ?, ?, ?)', [url, JSON.stringify(data), projectInfo.park_no, retryCount]);
            id = result.insertId;
        } else if (retryId) {
            // 更新现有记录
            await mysqlHelper.query('UPDATE retry_todo SET retry_count = ? WHERE id = ?', [retryCount, retryId]);
            id = retryId;
        }
        if (id && expireTime !== null) {
            // 设置Redis键
            await redisHelper.set(`retry_${id}`, '1', expireTime, dbIndex);
        }
    } catch (error) {
        // 处理数据库操作或Redis设置时可能出现的错误
        logger.error('添加到重试机制时发生错误', `url:${url} 入参：${JSON.stringify(data)} 项目信息:${JSON.stringify(projectInfo)} 错误信息:${error.message}`);
    }
}
/**
 * Redis监听失效时间并重发
 * @param {string} key
 * @returns {Promise<void>}
 */
async function listenKeyExpire(key) {
    const id = key.split('_')[1];
    const result = await mysqlHelper.excute('SELECT * FROM retry_todo WHERE id = ?', [id]);
    if (result.length === 0) {
        logger.warn('重试机制', '触发重试回调未找到对应的数据库信息', id);
        return;
    }
    const { url, data, park_no, retry_count } = result[0];
    const projectInfo = await redis.getProjectInfo(park_no);
    await retryRequest(url, data, projectInfo, retry_count + 1, id);
}

/**
 * 计算失效时间（单位：秒）
 * @param {number} retryCount 重试次数
 * @returns {number | null}
 */
function calculateExpireTime(retryCount) {
    if (retryCount < 5) return 5; // 第0-5次失败的失效时间为5秒
    if (retryCount < 10) return 60; // 5-10次是1分钟
    if (retryCount < 15) return 300; // 10-15次是5分钟
    if (retryCount < 20) return 1800; // 15-20次是半小时
    return null; // 超过20次不再重试
}

// (async () => {
//     const projectInfo = await mysqlHelper.query(`select * from project where park_no = '20230907739318'`);
//     const ret = await retryRequest(
//         'http://127.0.0.1:9981/api/pay_notify/LSY',
//         {
//             park_no: 123,
//             plate: '粤B88888',
//         },
//         projectInfo[0]
//     );
// })();

export default { post };

export { retryRequest, listenKeyExpire };
